#include "iceberg.h"

using namespace std;

Message Iceberg::Gama ( Message inputMessage )
{
	int i;
	Message message(inputMessage);

//	cout << "GAMA: " << message;

	for ( i = 0; i < message.binaryLenght; i += 4 )
	{
		S0 ( &message.binary[i] );
	}

	for ( i = 0; i < message.binaryLenght; i += 8 )
	{
		P8 ( &message.binary[i] );
	}

	for ( i = 0; i < message.binaryLenght; i += 4 )
	{
		S1 ( &message.binary[i] );
	}

	for ( i = 0; i < message.binaryLenght; i += 8 )
	{
		P8 ( &message.binary[i] );
	}	

	for ( i = 0; i < message.binaryLenght; i += 4 )
	{
		S0 ( &message.binary[i] );
	}

//	cout << " to " << message << endl;
	return message;
}

Message Iceberg::EK ( Message messageA, Message key )
{
	int i;
	Message message(messageA);

	P64 ( message.binary );

	for ( i = 0; i < 64; i += 4 )
	{
		D ( &message.binary[i] );
	}

	SK ( message, key );

	for ( i = 0; i < 64; i += 4 )
	{
		P4 ( &message.binary[i] );
	}

	P64 ( message.binary );

	return message;
}

Message Iceberg::TC ( Message inputMessage, Shift shift )
{
	bool temp[128];
	Message message(inputMessage);

	for ( int i = 0; i < 128; i++ )
	{
		temp[i] = message.binary[i];
	}

	for ( int i = 0; i < 128; i++ )
	{
		if ( shift == rightShift )
		{
			message.binary[i] = temp[ ( i + 8) % 128];
		}
		else if ( shift == leftShift )
		{
			message.binary[i] = temp[ ( 128 + i - 8) % 128];		
		}
	}

	return message;
}

Message Iceberg::BC ( Message inputMessage, Shift shift )
{
	Message message(inputMessage);

	TC ( message, shift );
	
	P128 ( message.binary );
	
	for ( int i = 0; i < 128; i += 4)
	{
		S0 ( &message.binary[i] );
	}
	
	P128 ( message.binary );
	
	TC ( message, shift );

	return message;
}

Message Iceberg::E ( Message inputMessage )
{
	int i, j;
	bool temp[128];
	Message message(inputMessage);

	for ( i = 0; i < 128; i++ )
	{
		temp[i] = message.binary[i];
	}
	
	delete [] message.binary;

	message.binary = new bool[64];
	message.binaryLenght = 64;

	for ( i = 0, j = 0; i < 128; i += 16 )
	{
			message.binary[j] = temp[i];
			message.binary[j + 1] = temp[i + 1];
			message.binary[j + 2] = temp[i + 2];
			message.binary[j + 3] = temp[i + 3];
			message.binary[j + 4] = temp[i + 4];
			message.binary[j + 5] = temp[i + 5];
			message.binary[j + 6] = temp[i + 6];
			message.binary[j + 7] = temp[i + 7];

			j += 8;
	}

	return message;
}

Message Iceberg::f ( Message inputMessage, int selection )
{
	int i;
	bool temp[64];
	Message message(inputMessage);

	for ( i = 0; i < 64; i++  )
	{
		temp[i] = message.binary[i];
	}

	for ( i= 0; i < 64; i += 4 )
	{
		if ( selection == 0 )
		{
			message.binary[i] = temp[i] ^ temp[i + 1];
			message.binary[i + 1] = temp[i + 1];
			message.binary[i + 2] = temp[i + 2] ^ temp[i + 3];
			message.binary[i + 3] = temp[i + 3];
		}
		else if ( selection == 1 )
		{
			message.binary[i] = temp[i] ^ temp[i + 1] ^ temp[i + 2];
			message.binary[i + 1] = temp[i + 1] ^ temp[i + 2];
			message.binary[i + 2] = temp[i + 2] ^ temp[i + 3] ^ temp[i];
			message.binary[i + 3] = temp[i + 3] ^ temp[i];
		}
	}

	return message;
}

Message Iceberg::SK ( Message inputMessage, Message key )
{
	int i;
	Message message(inputMessage);

	for ( i = 0; i < 64; i++ )
	{
		message.binary[i] = message.binary[i] ^ key.binary[i];
	}

	return message;
}


void Iceberg::S0 ( bool *binary )
{
		if ( binary[0] == false && binary[1] == false && binary[2] == false && binary[3] == false )
		{
			//0 => d
			binary[0] = binary[1] = binary[3] = true;
			binary[2] = false;
		}
		else if ( binary[0] == false && binary[1] == false && binary[2] == false && binary[3] == true )
		{
			//1 => 7
			binary[0] = false;
			binary[1] = binary[2]= binary[3] = true;
		}
		else if ( binary[0] == false && binary[1] == false && binary[3] == false && binary[2] == true )
		{
			//2 => 3
			binary[0] = binary[1] = false;
			binary[2] = binary[3] = true;			
		}
		else if ( binary[0] == false && binary[1] == false && binary[2] == true && binary[3] == true )
		{
			//3 => 2
			binary[0] = binary[1] = binary[3] = false;
			binary[2] = true;
		}
		else if ( binary[0] == false && binary[2] == false && binary[3] == false && binary[1] == true )
		{
			//4 => 9
			binary[0] = binary[3] = true;
			binary[1] = binary[2] = false;
		}
		else if ( binary[0] == false && binary[2] == false && binary[1] == true && binary[3] == true )
		{
			//5 => a
			binary[0] = binary[2] = true;
			binary[1] = binary[3] = false;
		}
		else if ( binary[0] == false && binary[3] == false && binary[1] == true && binary[2] == true)
		{
			//6 => c
			binary[0] = binary[1] = true;
			binary[2] = binary[3] = false;
		}
		else if ( binary[0] == false && binary[1] == true && binary[2] == true && binary[3] == true )
		{
			//7 => 1
			binary[0] = binary[1] = binary[2] = false;
			binary[3] = true;
		}
		else if ( binary[0] == true && binary[1] == false && binary[2] == false && binary[3] == false )
		{
			//8 => f
			binary[0] = binary[1] = binary[2] = binary[3] = true;
		}
		else if ( binary[0] == true && binary[3] == true && binary[1] == false && binary[2] == false )
		{
			//9 => 4
			binary[0] = binary[2] = binary[3] = false;
			binary[1] = true;
		}
		else if ( binary[0] == true && binary[2] == true && binary[1] == false && binary[3] == false )
		{
			//a => 5
			binary[0] = binary[2] = false;
			binary[1] = binary[3] = true;			
		}
		else if ( binary[1] == false && binary[0] == true && binary[2] == true && binary[3] == true )
		{
			//b => e
			binary[0] = binary[1] = binary[2] = true;
			binary[3] = false;
		}
		else if ( binary[0] == true && binary[1] == true && binary[2] == false && binary[3] == false )
		{
			//c => 6
			binary[0] = binary[3] = false;
			binary[1] = binary[2] = true;
		}
		else if ( binary[0] == true && binary[1] == true && binary[3] == true && binary[2] == false )
		{
			//d => 0
			binary[0] = binary[1] = binary[2] = binary[3] = false;
		}
		else if ( binary[0] == true && binary[1] == true && binary[2] == true && binary[3] == false )
		{
			//e => b
			binary[1] = false;
			binary[0] = binary[2] = binary[3] = true;
		}
		else if ( binary[0] == true && binary[1] == true && binary[2] == true && binary[3] == true )
		{
			//f => 8
			binary[0] = true;
			binary[1] = binary[2]= binary[3] = false;
		}
}

void Iceberg::S1 ( bool *binary )
{
		if ( binary[0] == false && binary[1] == false && binary[2] == false && binary[3] == false )
		{
			//0 => 4
			binary[0] = binary[2] = binary[3] = false;
			binary[1] = true;
		}
		else if ( binary[0] == false && binary[1] == false && binary[2] == false && binary[3] == true )
		{
			//1 => a
			binary[0] = binary[2] = true;
			binary[1] = binary[3] = false;
		}
		else if ( binary[0] == false && binary[1] == false && binary[3] == false && binary[2] == true )
		{
			//2 => f
			binary[0] = binary[1] = binary[2] = binary[3] = true;
		}
		else if ( binary[0] == false && binary[1] == false && binary[2] == true && binary[3] == true )
		{
			//3 => c
			binary[0] = binary[1] = true;
			binary[2] = binary[3] = false;
		}
		else if ( binary[0] == false && binary[2] == false && binary[3] == false && binary[1] == true )
		{
			//4 => 0
			binary[0] = binary[1] = binary[2] = binary[3] = false;
		}
		else if ( binary[0] == false && binary[2] == false && binary[1] == true && binary[3] == true )
		{
			//5 => d
			binary[0] = binary[1] = binary[3] = true;
			binary[2] = false;
		}
		else if ( binary[0] == false && binary[3] == false && binary[1] == true && binary[2] == true)
		{
			//6 => 9
			binary[0] = binary[3] = true;
			binary[1] = binary[2] = false;
		}
		else if ( binary[0] == false && binary[1] == true && binary[2] == true && binary[3] == true )
		{
			//7 => b
			binary[1] = false;
			binary[0] = binary[2] = binary[3] = true;
		}
		else if ( binary[0] == true && binary[1] == false && binary[2] == false && binary[3] == false )
		{
			//8 => e
			binary[0] = binary[1] = binary[2] = true;
			binary[3] = false;
		}
		else if ( binary[0] == true && binary[3] == true && binary[1] == false && binary[2] == false )
		{
			//9 => 6
			binary[0] = binary[3] = false;
			binary[1] = binary[2] = true;
		}
		else if ( binary[0] == true && binary[2] == true && binary[1] == false && binary[3] == false )
		{
			//a => 1
			binary[0] = binary[1] = binary[2] = false;
			binary[3] = true;
		}
		else if ( binary[1] == false && binary[0] == true && binary[2] == true && binary[3] == true )
		{
			//b => 7
			binary[0] = false;
			binary[1] = binary[2]= binary[3] = true;
		}
		else if ( binary[0] == true && binary[1] == true && binary[2] == false && binary[3] == false )
		{
			//c => 3
			binary[0] = binary[1] = false;
			binary[2] = binary[3] = true;
		}
		else if ( binary[0] == true && binary[1] == true && binary[3] == true && binary[2] == false )
		{
			//d => 5
			binary[0] = binary[2] = false;
			binary[1] = binary[3] = true;
		}
		else if ( binary[0] == true && binary[1] == true && binary[2] == true && binary[3] == false )
		{
			//e => 8
			binary[0] = true;
			binary[1] = binary[2]= binary[3] = false;
		}
		else if ( binary[0] == true && binary[1] == true && binary[2] == true && binary[3] == true )
		{
			//f => 2
			binary[0] = binary[1] = binary[3] = false;
			binary[2] = true;
		}
}

void Iceberg::D ( bool *binary )
{
	if ( binary[0] == false && binary[1] == false && binary[2] == false && binary[3] == false )
	{
		//0 => 0
		binary[0] = binary[1] = binary[2] = binary[3] = false;
	}
	else if ( binary[0] == false && binary[1] == false && binary[2] == false && binary[3] == true )
	{
		//1 => e
		binary[0] = binary[1] = binary[2] = true;
		binary[3] = false;
	}
	else if ( binary[0] == false && binary[1] == false && binary[2] == true && binary[3] == false )
	{
		//2 => d
		binary[0] = binary[1] = binary[3] = true;
		binary[2] = false;
	}
	else if ( binary[0] == false && binary[1] == false && binary[2] == true && binary[3] == true )
	{
		//3 => 3
		binary[0] = binary[1] = false;
		binary[2] = binary[3] = true;
	}
	else if ( binary[0] == false && binary[1] == true && binary[2] == false && binary[3] == false )
	{
		//4 => b
		binary[1] = false;
		binary[0] = binary[2] = binary[3] = true;
	}
	else if ( binary[0] == false && binary[1] == true && binary[2] == false && binary[3] == true )
	{
		//5 => 5
		binary[0] = binary[2] = false;
		binary[1] = binary[3] = true;
	}
	else if ( binary[0] == false && binary[1] == true && binary[2] == true && binary[3] == false )
	{
		//6 => 6
		binary[0] = binary[3] = false;
		binary[1] = binary[2] = true;
	}
	else if ( binary[0] == false && binary[1] == true && binary[2] == true && binary[3] == true )
	{
		//7 => 8
		binary[0] = true;
		binary[1] = binary[2] = binary[3] = false;
	}
	else if ( binary[0] == true && binary[1] == false && binary[2] == false && binary[3] == false )
	{
		//8 => 7
		binary[0] = false; 
		binary[1] = binary[2] = binary[3] = true;
	}
	else if ( binary[0] == true && binary[1] == false && binary[2] == false && binary[3] == true )
	{
		//9 => 9
		binary[0] = binary[3] = true;
		binary[1] = binary[2] = false;
	}
	else if ( binary[0] == true && binary[1] == false && binary[2] == true && binary[3] == false )
	{
		//a => a
		binary[0] = binary[2] = true;
		binary[1] = binary[3] = false;
	}
	else if ( binary[0] == true && binary[1] == false && binary[2] == true && binary[3] == true )
	{
		//b => 4
		binary[0] = binary[2] = binary[3] = false;
		binary[1] = true;
	}
	else if ( binary[0] == true && binary[1] == true && binary[2] == false && binary[3] == false )
	{
		//c => c
		binary[0] = binary[1] = true;
		binary[2] = binary[3] = false;
	}
	else if ( binary[0] == true && binary[1] == true && binary[2] == false && binary[3] == true )
	{
		//d => 2
		binary[0] = binary[1] = binary[3] = false;
		binary[2] = true;
	}
	else if ( binary[0] == true && binary[1] == true && binary[2] == true && binary[3] == false )
	{
		//e => 1
		binary[3] = true;
		binary[0] = binary[1] = binary[2] = false;
	}
	else if ( binary[0] == true && binary[1] == true && binary[2] == true && binary[3] == true )
	{
		//f => f
		binary[0] = binary[1] = binary[2] = binary[3] = true; 
	}
}

void Iceberg::P4 ( bool *binary )
{
	int i;

	bool temp[4];

	for ( i = 0; i < 4; i++ )
	{
		temp[i] = binary[i];
	}

	binary[0] = temp[1];
	binary[1] = temp[0];
	binary[2] = temp[3];
	binary[3] = temp[2];

}
void Iceberg::P8 ( bool *binary )
{
	int i;

	bool temp[8];

	for ( i = 0; i < 8; i++ )
	{
		temp[i] = binary[i];
	}

	binary[0] = temp[0];
	binary[1] = temp[1];
	binary[2] = temp[4];
	binary[3] = temp[5];
	binary[4] = temp[2];
	binary[5] = temp[3];
	binary[6] = temp[6];
	binary[7] = temp[7];
}


void Iceberg::P64 ( bool *binary )
{
	int i;

	bool temp[64];

	for ( i = 0; i < 64; i++ )
	{
		temp[i] = binary[i];
	}

	binary[0] = temp[0];
	binary[1] = temp[12];
	binary[2] = temp[23];
	binary[3] = temp[25];
	binary[4] = temp[38];
	binary[5] = temp[42];
	binary[6] = temp[53];
	binary[7] = temp[59];
	binary[8] = temp[22];
	binary[9] = temp[9];
	binary[10] = temp[26];
	binary[11] = temp[32];
	binary[12] = temp[1];
	binary[13] = temp[47];
	binary[14] = temp[51];
	binary[15] = temp[61];
	binary[16] = temp[24];
	binary[17] = temp[37];
	binary[18] = temp[18];
	binary[19] = temp[41];
	binary[20] = temp[55];
	binary[21] = temp[58];
	binary[22] = temp[8];
	binary[23] = temp[2];
	binary[24] = temp[16];
	binary[25] = temp[3];
	binary[26] = temp[10];
	binary[27] = temp[27];
	binary[28] = temp[33];
	binary[29] = temp[46];
	binary[30] = temp[48];
	binary[31] = temp[62];
	binary[32] = temp[11];
	binary[33] = temp[28];
	binary[34] = temp[60];
	binary[35] = temp[49];
	binary[36] = temp[36];
	binary[37] = temp[17];
	binary[38] = temp[4];
	binary[39] = temp[43];
	binary[40] = temp[50];
	binary[41] = temp[19];
	binary[42] = temp[5];
	binary[43] = temp[39];
	binary[44] = temp[56];
	binary[45] = temp[45];
	binary[46] = temp[29];
	binary[47] = temp[13];
	binary[48] = temp[30];
	binary[49] = temp[35];
	binary[50] = temp[40];
	binary[51] = temp[14];
	binary[52] = temp[57];
	binary[53] = temp[6];
	binary[54] = temp[54];
	binary[55] = temp[20];
	binary[56] = temp[44];
	binary[57] = temp[52];
	binary[58] = temp[21];
	binary[59] = temp[7];
	binary[60] = temp[34];
	binary[61] = temp[15];
	binary[62] = temp[31];
	binary[63] = temp[63];
}


void Iceberg::P128 ( bool *binary )
{
	int i;

	bool temp[128];

	for ( i = 0; i < 128; i++ )
	{
		temp[i] = binary[i];
	}

	binary[0] = temp[76];
	binary[1] = temp[110];
	binary[2] = temp[83];
	binary[3] = temp[127];
	binary[4] = temp[67];
	binary[5] = temp[114];
	binary[6] = temp[92];
	binary[7] = temp[97];
	binary[8] = temp[98];
	binary[9] = temp[65];
	binary[10] = temp[121];
	binary[11] = temp[106];
	binary[12] = temp[78];
	binary[13] = temp[112];
	binary[14] = temp[91];
	binary[15] = temp[82];
	binary[16] = temp[71];
	binary[17] = temp[101];
	binary[18] = temp[89];
	binary[19] = temp[126];
	binary[20] = temp[72];
	binary[21] = temp[107];
	binary[22] = temp[81];
	binary[23] = temp[118];
	binary[24] = temp[90];
	binary[25] = temp[124];
	binary[26] = temp[73];
	binary[27] = temp[88];
	binary[28] = temp[64];
	binary[29] = temp[104];
	binary[30] = temp[100];
	binary[31] = temp[85];
	binary[32] = temp[109];
	binary[33] = temp[87];
	binary[34] = temp[75];
	binary[35] = temp[113];
	binary[36] = temp[120];
	binary[37] = temp[66];
	binary[38] = temp[103];
	binary[39] = temp[115];
	binary[40] = temp[122];
	binary[41] = temp[108];
	binary[42] = temp[95];
	binary[43] = temp[69];
	binary[44] = temp[74];
	binary[45] = temp[116];
	binary[46] = temp[80];
	binary[47] = temp[102];
	binary[48] = temp[84];
	binary[49] = temp[96];
	binary[50] = temp[125];
	binary[51] = temp[68];
	binary[52] = temp[93];
	binary[53] = temp[105];
	binary[54] = temp[119];
	binary[55] = temp[79];
	binary[56] = temp[123];
	binary[57] = temp[86];
	binary[58] = temp[70];
	binary[59] = temp[117];
	binary[60] = temp[111];
	binary[61] = temp[77];
	binary[62] = temp[99];
	binary[63] = temp[94];
	binary[64] = temp[28];
	binary[65] = temp[9];
	binary[66] = temp[37];
	binary[67] = temp[4];
	binary[68] = temp[51];
	binary[69] = temp[43];
	binary[70] = temp[58];
	binary[71] = temp[16];
	binary[72] = temp[20];
	binary[73] = temp[26];
	binary[74] = temp[44];
	binary[75] = temp[34];
	binary[76] = temp[0];
	binary[77] = temp[61];
	binary[78] = temp[12];
	binary[79] = temp[55];
	binary[80] = temp[46];
	binary[81] = temp[22];
	binary[82] = temp[15];
	binary[83] = temp[2];
	binary[84] = temp[48];
	binary[85] = temp[31];
	binary[86] = temp[57];
	binary[87] = temp[33];
	binary[88] = temp[27];
	binary[89] = temp[18];
	binary[90] = temp[24];
	binary[91] = temp[14];
	binary[92] = temp[6];
	binary[93] = temp[52];
	binary[94] = temp[63];
	binary[95] = temp[42];
	binary[96] = temp[49];
	binary[97] = temp[7];
	binary[98] = temp[8];
	binary[99] = temp[62];
	binary[100] = temp[30];
	binary[101] = temp[17];
	binary[102] = temp[47];
	binary[103] = temp[38];
	binary[104] = temp[29];
	binary[105] = temp[53];
	binary[106] = temp[11];
	binary[107] = temp[21];
	binary[108] = temp[41];
	binary[109] = temp[32];
	binary[110] = temp[1];
	binary[111] = temp[60];
	binary[112] = temp[13];
	binary[113] = temp[35];
	binary[114] = temp[5];
	binary[115] = temp[39];
	binary[116] = temp[45];
	binary[117] = temp[59];
	binary[118] = temp[23];
	binary[119] = temp[54];
	binary[120] = temp[36];
	binary[121] = temp[10];
	binary[122] = temp[40];
	binary[123] = temp[56];
	binary[124] = temp[25];
	binary[125] = temp[50];
	binary[126] = temp[19];
	binary[127] = temp[3];

}
Message Iceberg::Encrypt ( Message key, Message message, int rounds )
{
//	cout << "KEY: " << key << "\nMESSAGE: " << message << endl;

	Message tempKey ( key );
//	cout << "TEMP KEY ( == KEY ) : " << tempKey << endl;
	Message selKey ( f( E ( key ), 1 ) );
//	cout << "SEL KEY: " << selKey << endl;
	Message temp ( SK ( message, selKey ) );
//	cout << "TEMP KEY: " << tempKey << endl;
	
//	cout << "E == " << E ( key ) << endl; 

	for ( int i = 0; i < rounds / 2; i++ )
	{
		tempKey = BC ( tempKey, leftShift );
		selKey = f ( E ( tempKey ), 1 );
		temp = EK ( Gama ( temp ), selKey );
	}

	for ( int i  = 0; i < ( rounds / 2 ) - 1; i++ )
	{
		tempKey = BC ( tempKey, rightShift );
		selKey = f ( E ( tempKey ), 1 );
		temp = EK ( Gama ( temp ), selKey );
	}

	tempKey = BC ( tempKey, rightShift );
	selKey = f ( E ( tempKey ), 0 );
	return SK ( Gama ( temp ), selKey );
}

Message Iceberg::Decrypt( Message key, Message message, int rounds )
{
	Message tempKey(key);
	Message selKey = f( E ( key ), 0 );

	Message temp = Gama ( SK ( message, selKey ) );

	for ( int i = 0; i < rounds / 2; i++ )
	{
		tempKey = BC ( tempKey, leftShift );
		selKey = f ( E ( tempKey ), 0 );
		temp = Gama ( EK ( temp , selKey ) );
	}

	for ( int i  = 0; i < ( rounds / 2 ) - 1; i++ )
	{
		tempKey = BC ( tempKey, rightShift );
		selKey = f ( E ( tempKey ), 0 );
		temp = Gama ( EK ( temp, selKey ) );
	}

	tempKey = BC ( tempKey, rightShift );
	selKey = f ( E ( tempKey ), 1 );

	return SK ( temp, selKey );
}

